#region license
# This file is part of Grawlix.
# 
# Grawlix is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
# 
# Grawlix is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public
# License along with Grawlix.  If not, see
# <http://www.gnu.org/licenses/>.
#endregion

"""OpenTK GameWindow, used as the main control loop for the client."""

namespace Grawlix.Client
import ConcurrentBoo
import Grawlix
import Grawlix.Meta
import Grawlix.Services
import Grawlix.Services.Rendering
import OpenTK
import OpenTK.Platform
import System

[Disposable]
transient class ClientWindow(GameWindow):
"""The client application, built on top of an OpenTK GameWindow."""
	
	def constructor():
	"""Creates a new GameWindow."""
		super()
		log Debug, "Client constructed."
	
	override def OnLoad(e as EventArgs):
	"""
	Initialize the game.
	Param e: Unused.
	"""
		try:
			configFile = "Properties/ClientServiceConfiguration.xml"
			configBuilder = \
				ServiceConfigurationBuilder.FromFile("Client", configFile)
			_provider = ServiceProvider(configBuilder.Configuration)
			_render = _provider.FindService[of IRenderDevice]()
			#_net = NetworkClient()
			_input = InputTranslator(self)
			_loader = _provider.FindService[of IGameLoader]()
			_loader.LoadLocal()
			OnResize(ResizeEventArgs(_viewport.Width, _viewport.Height))
		except exception:
			super.ExitAsync()
			log Fatal, "Exiting due to exception during client load:\n" + \
				exception
	
	override def OnUnload(e as EventArgs):
	"""
	Unload all modules.
	Param unused: Nothing important.
	"""
		try:
			if _provider is not null:
				_provider = null
			if _render is not null:
				_render = null
			#if _net is not null:
			#	_net.Dispose()
			#	_net = null
			if _input is not null:
				_input.Dispose()
				_input = null
			if _loader is not null:
				_loader = null
		except exception:
			log Warn, "Exception during client unload:\n" + exception
	
	override def OnUpdateFrame(e as UpdateFrameEventArgs):
	"""
	Update the state of the world and handle input.
	Param e: The parameters to the event.
	"""
		try:
			if _loader.HasQuit:
				unless super.IsExiting:
					super.ExitAsync()
					log Info, "Quit noticed on update, exiting."
				return
			
			elapsed = timespan.FromSeconds(e.Time)
			_game = _loader.Update(elapsed)
			
			# If there's no game, don't update
			return if _game is null
			
			# TODO: Start load of new game when connection requested
			
			# Scatter/Gather
			scatter = ActionPool()
			#scatter.Add({_net.Update(elapsed)})
			for domain as Domain in _game.Domains:
				scatter.Add() do:
					domain.Update(elapsed)
			scatter.Wait()
		except exception:
			_loader.LoadLocal()
			log Fatal, "Quitting due to exception on client update:\n" + \
				exception
	
	override def OnRenderFrame(e as RenderFrameEventArgs):
	"""
	Render and broadcast to the net.
	Param e: The parameters to the event.
	"""
		try:
			if _loader.HasQuit:
				unless super.IsExiting:
					super.ExitAsync()
					log Info, "Quit noticed on render, exiting."
				return
			
			#scatter = ActionPool()
			#scatter.Add() do:
			#	_net.Output()
			if _game is not null:
				main = _game.Main
				if main.Ready:
					_render.Clear()
					main.DirectAccess[of IRenderableArea](). \
						Render(_render, _viewport)
					_render.Finish()
					SwapBuffers()
			#scatter.Wait()
		except exception:
			_loader.LoadLocal()
			log Fatal, "Quiting due to exception on client render:\n" + \
				exception
	
	override def OnResize(e as ResizeEventArgs):
	"""
	Resize the OpenGL window.
	Param e: The parameters to the event.
	"""
		try:
			dimensions = Vector(System.Math.Abs(e.Width),
				System.Math.Abs(e.Height))
			_viewport = Rect(Vector(0, 0), dimensions)
			log Debug, "Resizing screen to ${dimensions.X}x${dimensions.Y}."
			if _render is not null:
				_render.Resize(dimensions)
				_render.Clear()
				_render.Finish()
				SwapBuffers()
		except exception:
			_loader.LoadLocal() if _loader is not null
			log Fatal, "Quiting due to exception on client resize:\n" + \
				exception
	
	private _game as Game
	"""The currently active game."""
	
	[getter(RenderDevice)]
	private _render as IRenderDevice
	"""The renderer."""
	
	private _provider as ServiceProvider
	"""The built-in ServiceProvider."""
	
	#[getter(Net)]
	#private _net as NetworkClient
	#"""The networking component."""
	
	private _loader as IGameLoader
	"""The game loader."""
	
	[getter(Input)]
	private _input as InputTranslator
	"""The input handler for the game window."""
	
	private _viewport as Rect
	"""The viewport rectangle."""











